/* using two stacks to implement simple expression evaluation algorithm*/

let Stack = require('../util/stack');
let operatorPattern = /[\+\-\*\/]/;
let validCharPattern = /[\(\)\+\-\*\/]/;

let evaluate = (str) => {
    let temp = '';
   
    if (str === 'undefined') {
        throw Error('undefined value');
    }
    let operandStack = new Stack();
    let operatorStack = new Stack();
    str = str.toString().split('').forEach(ch => {
        if (!isNaN(parseInt(ch, 10))) {
            temp += ch;
        } else if (validCharPattern.test(ch)) {
            if (temp) {
                operandStack.push(parseInt(temp, 10));
                temp = '';
            }
            if (operatorPattern.test(ch)) {
                operatorStack.push(ch);
            } else if (ch === ')') {
                operandStack.push(getExpressionResult(operatorStack.pop(), [operandStack.pop(), operandStack.pop()].reverse()));
            }
        }
    });
    if(operandStack.size() === 1 && operatorStack.isEmpty()){
        return operandStack.pop();
    } else {
        throw Error('Error');
    }
};

let getExpressionResult = (operator, operandArr) => {
    if (!operatorPattern.test(operator) || !Array.isArray(operandArr) || operandArr.length != 2 || operandArr.some(e => {
            isNaN(parseInt(e, 10))
        })) {
        throw Error('Illegal arguments');
    }
    switch (operator) {
        case '+':
            return operandArr.reduce((sum, current) => {
                return sum + parseInt(current, 10)
            }, 0);
        case '-':
            return parseInt(operandArr[0], 10) - parseInt(operandArr[1], 10);
        case '*':
            return operandArr.reduce((total, current) => {
                return total * current
            }, 1);
        case '/':
            return parseInt(operandArr[0], 10) / parseInt(operandArr[1], 10);
        default:
            throw Error("Unsupported");
    }
};


module.exports = evaluate;